/*!
 * # [486.预测赢家](https://leetcode.cn/problems/predict-the-winner/description/)
 *
 * @lc app=leetcode.cn id=486 lang=rust
 *
 * ## 难度
 * - Medium (59.30%)
 * - Likes:    582
 * - Dislikes: 0
 * - Total Accepted:    61.5K
 * - Total Submissions: 103.7K
 * - Testcase Example:  '[1,5,2]'
 *
 * ## 问题描述
 *
 * 给你一个整数数组 nums 。玩家 1 和玩家 2 基于这个数组设计了一个游戏。
 *
 * 玩家 1 和玩家 2 轮流进行自己的回合，玩家 1 先手。开始时，两个玩家的初始分值都是 0
 * 。每一回合，玩家从数组的任意一端取一个数字（即，nums[0] 或 nums[nums.length - 1]），取到的数字将会从数组中移除（数组长度减
 * 1 ）。玩家选中的数字将会加到他的得分上。当数组中没有剩余数字可取时，游戏结束。
 *
 * 如果玩家 1 能成为赢家，返回 true 。如果两个玩家得分相等，同样认为玩家 1 是游戏的赢家，也返回 true
 * 。你可以假设每个玩家的玩法都会使他的分数最大化。
 *
 * ## 示例 1：
 * - 输入：nums = [1,5,2]
 * - 输出：false
 * - 解释：一开始，玩家 1 可以从 1 和 2 中进行选择。
 * 如果他选择 2（或者 1 ），那么玩家 2 可以从 1（或者 2 ）和 5 中进行选择。如果玩家 2 选择了 5 ，那么玩家 1 则只剩下 1（或者 2
 * ）可选。
 * 所以，玩家 1 的最终分数为 1 + 2 = 3，而玩家 2 为 5 。
 * 因此，玩家 1 永远不会成为赢家，返回 false 。
 *
 * ## 示例 2：
 * - 输入：nums = [1,5,233,7]
 * - 输出：true
 * - 解释：玩家 1 一开始选择 1 。然后玩家 2 必须从 5 和 7 中进行选择。无论玩家 2 选择了哪个，玩家 1 都可以选择 233 。
 * 最终，玩家 1（234 分）比玩家 2（12 分）获得更多的分数，所以返回 true，表示玩家 1 可以成为赢家。
 *
 * ## 提示：
 * - 1 <= nums.length <= 20
 * - 0 <= nums[i] <= 10^7
 *
 */

struct Solution;

// @lc code=start
impl Solution {
    /// # 预测赢家
    /// - 动态规划
    /// 1. 令dp[i][j]表示剩下nums[i..j]石子时，当前玩家所得分数的最大差；
    /// 2. 则dp[0][n-1] > 0时，表示alice赢得比赛；
    /// 3. i>j时, 无意义，dp[i][j] = 0;
    /// 4. i==j时, 只剩下这个, dp[i][j] = nums[i];
    /// 5. i<j时, 当前玩家有2种取法，选其中最大的取法:
    ///    dp[i][j] = max(nums[i] - dp[i+1][j], nums[j] - dp[i][j-1])
    pub fn predict_the_winner(nums: Vec<i32>) -> bool {
        let n = nums.len();
        let mut dp = vec![vec![0_i32; n]; n];

        for i in (0..n - 1).rev() {
            for j in i..n {
                dp[i][j] = if i == j {
                    nums[i]
                } else {
                    std::cmp::max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1])
                };
            }
        }

        dp[0][n - 1] >= 0
    }
}
// @lc code=end

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test() {
        assert_eq!(Solution::predict_the_winner(vec![1, 5, 2]), false);
        assert_eq!(Solution::predict_the_winner(vec![1, 5, 233, 7]), true);
        assert_eq!(Solution::predict_the_winner(vec![0]), true);
    }
}
